﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.ActionManagement;
using JetBrains.Annotations;
using JetBrains.Application;
using JetBrains.Application.DataContext;
using JetBrains.DataFlow;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Feature.Services.ContextNavigation;
using JetBrains.ReSharper.Feature.Services.Occurences;
using JetBrains.ReSharper.Feature.Services.Search;
using JetBrains.ReSharper.Features.Finding.ExecutionHosting;
using JetBrains.ReSharper.Features.Finding.GoToDeclaredElement;
using JetBrains.ReSharper.Psi.Modules;
using JetBrains.TextControl;
using JetBrains.Util;
using JetBrains.Util.Special;
using DataConstants = JetBrains.ProjectModel.DataContext.DataConstants;
using ShellComponentsEx = JetBrains.UI.Application.ShellComponentsEx;

namespace MugenMvvmToolkit.ReSharper.Navigations
{
    [ContextNavigationProvider]
    public class GotoViewModelsNavigationProvider : INavigateFromHereProvider
    {
        #region Fields

        private readonly IShellLocks _locks;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="ViewViewModelNavigationProvider" /> class.
        /// </summary>
        public GotoViewModelsNavigationProvider([NotNull] IShellLocks locks)
        {
            if (locks == null) throw new ArgumentNullException("locks");
            _locks = locks;
        }

        #endregion

        #region Implementation of IWorkflowProvider<ContextNavigation,out NavigationActionGroup>

        public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
        {
            ISolution solution = dataContext.GetData(DataConstants.SOLUTION);
            IProject project = dataContext.GetData(DataConstants.Project);
            var psiModule = project.IfNotNull(p => p.GetPsiModules().FirstOrDefault());
            if (solution == null || project == null || psiModule == null)
                return Enumerable.Empty<ContextNavigation>();

            TypeProvider provider = TypeProvider.Create(psiModule, psiModule.GetContextFromModule());
            return new[]
            {
                new ContextNavigation(UiResources.GotoViewModels, ActionIdConstants.GotoViewModelsNavigationAction,
                    NavigationActionGroup.Important, () => GotoViewModels(dataContext, solution, provider))
            };
        }

        #endregion

        #region Methods

        private void GotoViewModels(IDataContext context, ISolution solution, TypeProvider typeProvider)
        {
            ITextControl data = context.GetData(JetBrains.TextControl.DataContext.DataConstants.TEXT_CONTROL);
            if (data == null)
                return;
            List<IOccurence> list = typeProvider.FindAllViewModels()
                .OrderBy(@class => @class.Module.Name)
                .ThenBy(@class => @class.ShortName)
                .Select(element => new DeclaredElementOccurence(element))
                .Cast<IOccurence>()
                .ToList();

            if (list.IsEmpty())
            {
                ShellComponentsEx.Tooltips(Shell.Instance.Components)
                    .ShowAtCaret(EternalLifetime.Instance, UiResources.GotoViewModelsEmpty, data, _locks,
                        Shell.Instance.GetComponent<IActionManager>());
            }
            else
            {
                DefaultNavigationExecutionHost.Instance.ShowContextPopupMenu(context, list,
                    () =>
                        new GotoDeclaredElementsBrowserDescriptor(solution,
                            ActionIdConstants.GotoViewModelsNavigationAction, "IViewModel", list),
                    OccurencePresentationOptions.DefaultOptions, true, UiResources.GotoViewModels);
            }
        }

        #endregion
    }
}